﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Index;
using Lucandra.Net.Connection;
using Lucandra.Net.Connection.Pooling;

namespace Lucandra.Net
{
    internal sealed class LucandraTermEnum : TermEnum
    {
        #region Properties [public]

        public string IndexName { get; private set; }
        public bool IsOpen { get; private set; }
        public Term CurrentTerm
        {
            get { return this.TermInfoReader.CurrentTerm; }
        }
        public LucandraTermInfo CurrentTermInfo
        {
            get { return this.TermInfoReader.CurrentTermInfo; }
        }

        #endregion
        #region Properties [private]

        private TermInfoReader @TermInfoReader { get; set; }
        private LucandraReader @LucandraReader { get; set; }

        #endregion

        #region Constructors

        public LucandraTermEnum(LucandraReader lucandraReader)
            : this(lucandraReader, Settings.DefaultTermReadAhead)
        {
        }

        public LucandraTermEnum(LucandraReader lucandraReader, int maxReadAhead)
        {
            this.LucandraReader = lucandraReader;
            this.IndexName = lucandraReader.IndexName;

            this.TermInfoReader = new TermInfoReader(this.IndexName, maxReadAhead, Settings.UseKeyspacePerIndex, lucandraReader.Keyspace);
            this.IsOpen = true;
        }

        public LucandraTermEnum(LucandraReader lucandraReader, Term term)
            : this(lucandraReader, term, Settings.DefaultTermReadAhead)
        {
        }

        public LucandraTermEnum(LucandraReader lucandraReader, Term term, int maxReadAhead)
            : this(lucandraReader, maxReadAhead)
        {
            this.TermInfoReader.PositionAt(term);
        }

        #endregion

        [Obsolete("This method is obsolete and will be removed in 3.0.", true)]
        public override bool SkipTo(Term target)
        {
            throw new NotImplementedException();
        }

        public override bool Next()
        {
            this.AssertIsOpen();

            return this.TermInfoReader.Next();
        }

        public override Term Term()
        {
            this.AssertIsOpen();

            return this.TermInfoReader.CurrentTerm;
        }

        public override int DocFreq()
        {
            this.AssertIsOpen();
            if (this.TermInfoReader.CurrentTermInfo == null)
                return 0;
            return this.TermInfoReader.CurrentTermInfo.DocumentCount;
        }

        public override void Close()
        {
            this.AssertIsOpen();

            //this.TermInfoReader = null;
            //this.LucandraReader = null;
            //this.IndexName = null;
        }

        private void AssertIsOpen()
        {
            if (!this.IsOpen)
                throw new InvalidOperationException("This LucandraTermEnum has been closed.");
        }

        public IEnumerable<LucandraTermInfo.LucandraTermInfoDocument> GetTermInfoDocuments()
        {
            if (this.CurrentTermInfo == null || this.CurrentTermInfo.DocumentCount == 0)
                return null;

            int[] documentIDs = new int[this.CurrentTermInfo.DocumentCount];
            int index = 0;

            var documentMap = new Dictionary<int, LucandraTermInfo.LucandraTermInfoDocument>();

            foreach (var document in this.CurrentTermInfo.Documents)
            {
                int documentNumber = this.LucandraReader.AddDocumentMapping(document, this.CurrentTermInfo.FieldName);
                documentMap[documentNumber] = document;
                documentIDs[index] = documentNumber;
                index++;
            }

            // Sort the document IDs.
            documentIDs = documentIDs.OrderBy(c => c).ToArray();

            // Create a sorted list of documents.
            var documents = new List<LucandraTermInfo.LucandraTermInfoDocument>();
            for (int i = 0; i < this.CurrentTermInfo.DocumentCount; i++)
                documents.Add(documentMap[documentIDs[i]]);

            return documents;
        }
    }
}
